Function module ZSTB_RFC_READ_DATA_SOURCE

Import
I_OSOURCE           LIKE  ROOSOURCE-OLTPSOURCE
I_REQUNR            LIKE  RSIODYNP4-REQUNR      DEFAULT 'STB_TEST'
I_MAXSIZE           LIKE  RSIODYNP4-MAXSIZE     DEFAULT '100'
I_MAXFETCH          LIKE  RSIODYNP4-CALLS       DEFAULT '10'
I_UPDMODE           LIKE  RSIODYNP4-UPDMODE     DEFAULT 'F'
I_FIELD_SEPARATOR   TYPE  ADD_SERVICE           DEFAULT '|'
I_TARGET_SYS        LIKE  RSIODYNP4-RLOGSYS     OPTIONAL
I_CALLBACK_URL      TYPE  EPM_URL               OPTIONAL
I_PARENT_SESSION_ID TYPE  CHAR255               OPTIONAL
I_STRING_QUALIFIER  TYPE  C1                    DEFAULT ''

Export
SUBRC	LIKE	SYST-SUBRC
E_ERROR	TYPE	STRING

Tables
I_T_SELECT	LIKE	RSSELECT
I_T_FIELDS	LIKE	RSFIELDSEL
E_T_DATA	LIKE	ZSTB_DS_TABLE

Source Code
function ZSTB_RFC_READ_DATA_SOURCE.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(I_OSOURCE) LIKE  ROOSOURCE-OLTPSOURCE
*"     VALUE(I_REQUNR) LIKE  RSIODYNP4-REQUNR DEFAULT 'STB_TEST'
*"     VALUE(I_MAXSIZE) LIKE  RSIODYNP4-MAXSIZE DEFAULT '100'
*"     VALUE(I_MAXFETCH) LIKE  RSIODYNP4-CALLS DEFAULT '10'
*"     VALUE(I_UPDMODE) LIKE  RSIODYNP4-UPDMODE DEFAULT 'F'
*"     VALUE(I_FIELD_SEPARATOR) TYPE  ADD_SERVICE DEFAULT '|'
*"     VALUE(I_TARGET_SYS) LIKE  RSIODYNP4-RLOGSYS OPTIONAL
*"     VALUE(I_CALLBACK_URL) TYPE  EPM_URL OPTIONAL
*"     VALUE(I_PARENT_SESSION_ID) TYPE  CHAR255 OPTIONAL
*"     VALUE(I_STRING_QUALIFIER) TYPE  C1 DEFAULT ''
*"  EXPORTING
*"     VALUE(SUBRC) LIKE  SYST-SUBRC
*"     VALUE(E_ERROR) TYPE  STRING
*"  TABLES
*"      I_T_SELECT STRUCTURE  RSSELECT OPTIONAL
*"      I_T_FIELDS STRUCTURE  RSFIELDSEL OPTIONAL
*"      E_T_DATA STRUCTURE  ZSTB_DS_TABLE OPTIONAL
*"----------------------------------------------------------------------
*-- Local Variables
  data: vl_source       type roosourcer.
  data: wa_source       type roosource.
  data: vl_lines        type i,
        vl_index(8)     type n,
        vl_length       type i,
        vl_idfield(16)  type c,
        returnrowstring type string,
        datafieldstring type string,
        dataline        like e_t_data,
        callback_url  type epm_url,
        string_qualifier(255)  type c,
        callback_parent_session_id  type char255,
        callback_error(255)  type c.

***** 1st metadata extraction ****

* get metadata about the input data-source (DS)
* roosource : SAP internal metadata table
*             see : https://www.se80.co.uk/saptables/r/roos/roosource.htm
*             see : https://www.sapdatasheet.org/abap/tabl/roosource.html
* wa_source : structure to store DC information
  vl_source = i_osource.
  select single * into wa_source
      from roosource
      where oltpsource = vl_source.

* check we get some information about the DS
* if no information, set error code and message
* sy-subrc : internal SAP variable about last command result
*            0 for no error ; any other number is for a specific error
* subrc : output value for error code
  if sy-subrc ne 0.
    message i001(ls) with 'ERROR: NO FOUND STRUCTURE'.
    subrc = 4.
    exit.
  endif.

*-- Get structure
  data: wf_ref  type ref to data,
        wf_line type ref to data.

  data: go_struct type ref to cl_abap_structdescr,
        gt_comp   type abap_component_tab,
        gs_comp   type abap_componentdescr.

  field-symbols: <f_src>      type standard table,
                 <fs_tab>    type standard table,
                  <datafield> type any,
                  <datarow>   type any,
                  <fs_line>   type any.
*-- Export program

* extract last information about the DS
* wa_source-exstruct : returned table describing the DC structure (ie fields and types)
* wf_line : temporary table to store the DC structure (ie copy of fields and types)
* TODO : confirm "wf_line" is not use later, if so delete it ( ¡ beware <fs_tab> is used later ! )
  create data wf_ref type table of (wa_source-exstruct). "Dynamic Itab
  assign wf_ref->* to <fs_tab>.
  create data wf_line like line of <fs_tab>. "Dynamic Work area

***** 2nd metadata extraction ****

  data: l_s_roosgen   type rsaot_s_roosgen,
        l_t_roosgen   type rsaot_t_roosgen,
        l_tfstruc     type sbiwm_structure.

* continue to get DC metadata
* RSA1_SINGLE_OLTPSOURCE_GET : internal function to get metadata about the DC
*                              see : https://www.se80.co.uk/sapfms/r/rsa1/rsa1_single_oltpsource_get.htm
*                              see : https://www.sapdatasheet.org/abap/func/rsa1_single_oltpsource_get.html
* l_t_roosgen : pointer to the metadata
* l_s_roosgen : temporary table to store the returned metadata
  call function 'RSA1_SINGLE_OLTPSOURCE_GET'
       exporting
            i_oltpsource = i_osource
       importing
            e_t_roosgen  = l_t_roosgen.

  read table l_t_roosgen into l_s_roosgen index 1.

* load DC structure regarding last returned metadata
* tfmethode  : type of structure (I for IDOC ; ¿ T for table ?)
*              WARNING : i did not yet find information about rsaot_s_roosgen
* l_tfstruc : store DC structure description
  case l_s_roosgen-tfmethode.
    when 'I'.
      l_tfstruc = l_s_roosgen-tfstridoc.
    when 'T'.
      l_tfstruc = l_s_roosgen-tfstruc.
  endcase.

* get field list about DC
* fill_field_list : internal sub-routine to extract field list
* saplrsap : internal SAP function about data transfert
*            see : https://www.sapdatasheet.org/abap/prog/saplrsap.html
* i_t_fields : table to store DC fields list
  perform fill_field_list(saplrsap) tables i_t_fields
                                    using  l_tfstruc.

* NOTE : all metadata tables shoulb correspond one to each other
* wf_line : 1st extract
* i_t_fields : 2nd extract

***** extract DS data *****
* RSFH_GET_DATA_SIMPLE : internal SAP function to get data from DS
*                        see : https://www.se80.co.uk/sapfms/r/rsfh/rsfh_get_data_simple.htm
*                        see : https://www.sapdatasheet.org/abap/func/rsfh_get_data_simple.html
* i_t_field : filter fields list to keep in output
* callback URL is setted, ie we send data back to Stambia WS
if i_callback_url is not initial.
* INFO : exporting to memory is creating a reference to use a variable in sub programs
*        so an can be as a globalization of a variable
*       usually, iti is an anti-pattern, but we need it here because 'RSFH_GET_DATA_SIMPLE' is not designed to take a callback URL in input
  callback_url = i_callback_url.
  export callback_url to memory id 'ZSTB_DS_EXPORT_URL'.
*   globalize string qualifier (CSV format)
  string_qualifier = i_string_qualifier.
  export string_qualifier to memory id 'ZSTB_DS_EXPORT_STRING_QUALIFIER'.
* if Stambia send a session ID, also globalize session ID
  if i_parent_session_id is not initial.
    callback_parent_session_id = i_parent_session_id.
    export callback_parent_session_id to memory id 'ZSTB_DS_EXPORT_PARENT_SESSION_ID'.
  endif.
* result data is sent back to Stambia inside this function
  call function 'RSFH_GET_DATA_SIMPLE'
    exporting
            i_requnr              = i_requnr
            i_osource             = i_osource
            i_maxsize             = i_maxsize
            i_maxfetch            = i_maxfetch
            i_updmode             = i_updmode
            i_rlogsys             = i_target_sys
    tables
            i_t_select            = i_t_select
            i_t_field             = i_t_fields
    exceptions
            generation_error      = 1
            interface_table_error = 2
            metadata_error        = 3
            no_authority          = 4
            others                = 5.
* callback URL not in input, ie we store output into e_t_data table
else.
      call function 'RSFH_GET_DATA_SIMPLE'
       exporting
            i_requnr              = i_requnr
            i_osource             = i_osource
            i_maxsize             = i_maxsize
            i_maxfetch            = i_maxfetch
            i_updmode             = i_updmode
            i_rlogsys             = i_target_sys
       tables
            i_t_select            = i_t_select
            i_t_field             = i_t_fields
            e_t_data              = <fs_tab>
       exceptions
            generation_error      = 1
            interface_table_error = 2
            metadata_error        = 3
            no_authority          = 4
            others                = 5.

 endif.

**** error management area ****

if sy-subrc <> 0.
    case sy-subrc.
      when '1' or '2' or '3' or '4'.
        message id sy-msgid type 'I' number sy-msgno
        with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.

      when others.
        message id sy-msgid type 'I' number sy-msgno
        with sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.

    endcase.
  endif.

* if we used "e_t_data" instead of callback URL, format it to CSV
* this is the same method is in "ZSTB_DS_HTTP_CALLBACK" (refer to it for more technicel details)
* TODO : use a subroutine to factorize code
 if <fs_tab> is assigned.
    read table <fs_tab> assigning <fs_line> index 1.
    if <fs_line> is assigned.
      go_struct ?= cl_abap_typedescr=>describe_by_data( <fs_line> ).
      gt_comp = go_struct->get_components( ).
      describe table gt_comp lines vl_lines.
    endif.
    loop at <fs_tab> assigning <datarow>.
      clear dataline.
      vl_index = vl_index + 1.
     do vl_lines times.
        assign component sy-index of structure <datarow> to <datafield>.
        datafieldstring = <datafield>.
        if returnrowstring is initial and sy-index = 1.
          concatenate returnrowstring datafieldstring
                 into returnrowstring.
        else.
          concatenate returnrowstring i_field_separator datafieldstring
                 into returnrowstring.
        endif.
      enddo.
      if returnrowstring is not initial.
        dataline-fieldsrow = returnrowstring.
        dataline-seqnr = vl_index.
        insert dataline into table e_t_data.
        clear returnrowstring.
      endif.
    endloop.
    if returnrowstring is not initial.
      dataline = returnrowstring.
      insert dataline into table e_t_data.
      clear returnrowstring.
    endif.
  endif.

**** end of functionnal business ****
* following code is just technical stuff : error management & data cleaning

 import callback_error from memory id 'ZSTB_DS_EXPORT_ERROR'.

  if callback_error is not initial.
    e_error = callback_error.
  else.
    e_error = 'no_error'.
  endif.

*-- Free memory
  free memory id 'SNF2_OLD_OBJECT'.
  free memory id 'RSFH_DATA'.
*  FREE MEMORY ID 'Z_TAB'.
***

endfunction.
*INCLUDE bdcrecxy .